/*
 * json.h
 *
 *  Created on: Aug 2, 2010
 *      Author: Pierre Lindenbaum PhD
 *              plindenbaum@yahoo.fr
 *              http://plindenbaum.blogspot.com
 *              
 */
#ifndef CORE_JSON_H
#define CORE_JSON_H

#include <iostream>
#include <map>
#include <vector>
#include "core/io/escape.h"

namespace u915{ namespace json {


enum NodeType {nullNode,intNode,realNode,boolNode,stringNode,arrayNode,objectNode};

class Node
    {
    protected:
	Node()
	    {
	    }
    public:
	  virtual ~Node()
	      {
	      }
	  virtual bool isComplex() const=0;
	  virtual bool isLeaf() const
	      {
	      return !isComplex();
	      }
	  virtual bool isNull() const { return type()==nullNode;}
	  virtual bool isString() const { return type()==stringNode;}
	  virtual bool isInt() const { return type()==intNode;}
	  virtual bool isReal() const { return type()==realNode;}
	  virtual bool isBool() const { return type()==boolNode;}
	  virtual bool isArray() const { return type()==arrayNode;}
	  virtual bool isObject() const { return type()==objectNode;}
	  virtual NodeType type() const=0;
    };

std::ostream& operator << (std::ostream& out,const Node& o)
    {
    return out;
    }

typedef Node* NodePtr;

class LeafNode:public Node
    {
    protected:
	LeafNode()
   	    {
   	    }
       public:
   	  virtual ~LeafNode()
   	      {
   	      }
   	 virtual bool isComplex() const
	     {
   	     return false;
	     }
   	  virtual NodeType type() const=0;
    };

class NilNode:public LeafNode
    {
    public:
	NilNode()
		{
		}
	  virtual ~NilNode()
	      {
	      }
	  virtual NodeType type() { return nullNode;}
	  friend std::ostream& operator << (std::ostream& out,const NilNode& o);
    };

std::ostream& operator << (std::ostream& out,const NilNode& o)
    {
    out <<  "null";
    return out;
    }

class IntNode:public LeafNode
    {
    private:
	    long _value;
    public:
	    IntNode(long v):_value(v)
		{
		}
	  virtual ~IntNode()
	      {
	      }
	  virtual long value() const
	      {
	      return _value;
	      }
	  virtual NodeType type() { return intNode;}
	  friend std::ostream& operator << (std::ostream& out,const IntNode& o);
    };

std::ostream& operator << (std::ostream& out,const IntNode& o)
    {
    out <<  o.value();
    return out;
    }

class RealNode:public LeafNode
    {
    private:
	    double _value;
    public:
	    RealNode(double v):_value(v)
		{
		}
	  virtual ~RealNode()
	      {
	      }
	  virtual double value() const
	      {
	      return _value;
	      }
	  virtual NodeType type() { return realNode;}
	  friend std::ostream& operator << (std::ostream& out,const RealNode& o);
    };

std::ostream& operator << (std::ostream& out,const RealNode& o)
    {
    out <<  o.value();
    return out;
    }


class BoolNode:public LeafNode
    {
    private:
	    bool _value;
    public:
	    BoolNode(bool v):_value(v)
		{
		}
	  virtual ~BoolNode()
	      {
	      }
	  virtual bool value() const
	      {
	      return _value;
	      }
	  virtual NodeType type() { return boolNode;}
	  friend std::ostream& operator << (std::ostream& out,const BoolNode& o);
    };

std::ostream& operator << (std::ostream& out,const BoolNode& o)
    {
    out <<  (o.value()?"true":"false");
    return out;
    }

class StringNode:public LeafNode
    {
    private:
	    std::string _value;
    public:
	    StringNode(std::string v):_value(v)
		{
		}
	  virtual ~StringNode()
	      {
	      }
	  virtual const std::string& value() const
	      {
	      return _value;
	      }
	  virtual NodeType type() { return boolNode;}
	  friend std::ostream& operator << (std::ostream& out,const StringNode& o);
    };
std::ostream& operator << (std::ostream& out,const StringNode& o)
    {
    out << u915::io::escape(o.value());
    return out;
    }

class ComplexNode:public Node
    {
    protected:
	ComplexNode()
   	    {
   	    }
       public:
   	  virtual ~ComplexNode()
   	      {
   	      }
   	virtual bool isComplex() const
	     {
	     return true;
	     }
   	  virtual NodeType type() const=0;

    };

class ArrayNode:public ComplexNode
    {
    private:
	    std::vector<NodePtr> array;
    public:
	    ArrayNode()
		{
		}
	  virtual ~ArrayNode()
	      {
	      while(!array.empty())
		  {
		  NodePtr a=array.back();
		  delete a;
		  array.pop_back();
		  }
	      }
	  virtual void push_back(NodePtr node)
	      {
	      array.push_back(node);
	      }
	  virtual int size() const
	      {
	      return array.size();
	      }
	  virtual const NodePtr at(int index) const
	      {
	      return array.at(index);
	      }
	  virtual NodeType type() { return arrayNode;}
	  friend std::ostream& operator << (std::ostream& out,const ArrayNode& o);
    };


std::ostream& operator << (std::ostream& out,const ArrayNode& o)
    {
    bool first=true;
    std::vector<NodePtr>::const_iterator r=o.array.begin();
    std::vector<NodePtr>::const_iterator r_end=o.array.end();
    out << "[";
    while(r!=r_end)
	{
	if(!first) out<<',';
	first=false;
	out << (*(r));
	++r;
	}
    out << "]";
    return out;
    }

class ObjectNode:public ComplexNode
    {
    private:
	    std::map<std::string,NodePtr> map;
    public:
	    ObjectNode()
		{
		}
	  virtual ~ObjectNode()
	      {
	      std::map<std::string,NodePtr>::iterator r=map.begin();
	      std::map<std::string,NodePtr>::iterator r_end=map.end();
	      while(r!=r_end)
		  {
		  delete r->second;
		  ++r;
		  }
	      map.clear();
	      }
	  virtual int size() const
	      {
	      return map.size();
	      }
	  virtual void put(std::string key,NodePtr value)
	      {
	      map.insert(std::make_pair<std::string,NodePtr>(key,value));
	      }
	  virtual const NodePtr get(const char *key) const
	      {
	      std::map<std::string,NodePtr>::const_iterator r=map.find(key);
	      if(r==map.end()) return 0;
	      return r->second;
	      }
	  virtual NodeType type() { return objectNode;}
	  friend std::ostream& operator << (std::ostream& out,const ObjectNode& o);
    };

std::ostream& operator << (std::ostream& out,const ObjectNode& o)
    {
    bool first=true;
    std::map<std::string,NodePtr>::const_iterator r=o.map.begin();
    std::map<std::string,NodePtr>::const_iterator r_end=o.map.end();
    out << "{";
    while(r!=r_end)
	{
	if(!first) out<<',';
	first=false;
	out << "\"" << u915::io::escape(r->first)  << "\":";
	out << (*(r->second));
	++r;
	}
    out << "}";
    return out;
    }

}}

#endif

